﻿using System;
using System.ComponentModel;
using System.Windows.Forms;
using DevExpress.XtraBars.Ribbon;
using DevExpress.XtraGrid.Views.Grid;
using Loki.Commands;
using Loki.Engine;
using Loki.Utils;

namespace Loki.UI.Win
{
    public class RibbonViewBase : RibbonForm, IView, IWinform
    {
        #region Properties
        /// <summary>
        /// Gets or sets a value indicating whether the form name is binded on VM state.
        /// </summary>
        /// <value>
        ///   <c>true</c> if the form name is binded on VM state; otherwise, <c>false</c>.
        /// </value>
        [EditorBrowsable(EditorBrowsableState.Always)]
        protected bool BindNameOnVMState
        {
            get;
            set;
        }
        #endregion

        #region Controls

        protected internal DevExpress.Utils.ToolTipController TOO_Controller;
        protected RibbonControl RBN_MainRibbon;
        private IContainer components;

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.TOO_Controller = new DevExpress.Utils.ToolTipController(this.components);
            this.RBN_MainRibbon = new DevExpress.XtraBars.Ribbon.RibbonControl();
            ((System.ComponentModel.ISupportInitialize)(this.RBN_MainRibbon)).BeginInit();
            this.SuspendLayout();
            // 
            // ribbonControl1
            // 
            this.RBN_MainRibbon.ExpandCollapseItem.Id = 0;
            this.RBN_MainRibbon.ExpandCollapseItem.Name = "";
            this.RBN_MainRibbon.Items.AddRange(new DevExpress.XtraBars.BarItem[] {
            this.RBN_MainRibbon.ExpandCollapseItem});
            this.RBN_MainRibbon.Location = new System.Drawing.Point(0, 0);
            this.RBN_MainRibbon.MaxItemId = 1;
            this.RBN_MainRibbon.Name = "ribbonControl1";
            this.RBN_MainRibbon.RibbonStyle = DevExpress.XtraBars.Ribbon.RibbonControlStyle.Office2010;
            this.RBN_MainRibbon.Size = new System.Drawing.Size(934, 49);
            this.RBN_MainRibbon.ToolTipController = this.TOO_Controller;
            // 
            // RibbonViewBase
            // 
            this.AllowDisplayRibbon = false;
            this.ClientSize = new System.Drawing.Size(934, 564);
            this.Controls.Add(this.RBN_MainRibbon);
            this.Name = "RibbonViewBase";
            this.Ribbon = this.RBN_MainRibbon;
            ((System.ComponentModel.ISupportInitialize)(this.RBN_MainRibbon)).EndInit();
            this.ResumeLayout(false);

        }
        #endregion

        public RibbonViewBase()
        {
            BindNameOnVMState = true;
            InitializeComponent();
            Commands = new CommandManager();
            DataBinder = new Databinder();
            BindingChanging += RemoveBindings;
            BindingChanged += InitializeBindings;
        }

        #region Log
        /// <summary>
        /// Gets the logger.
        /// </summary>
        /// <value>The logger.</value>
        protected ILog Log
        {
            get
            {
                if (_Log == null)
                    _Log = LokiServices.Logger.GetLogger("Loki.UI.Win.ViewBase");
                return _Log;
            }
        }
        private static ILog _Log = null;
        #endregion

        #region Binding
        /// <summary>
        /// Gets the data binder.
        /// </summary>
        protected internal Databinder DataBinder
        {
            get;
            private set;
        }

        #region BindingChanged
        private readonly object BindingChangedEventLock = new object();
        private EventHandler BindingChangedEvent;

        public event EventHandler BindingChanged
        {
            add
            {
                lock (BindingChangedEventLock)
                {
                    BindingChangedEvent += value;
                }
            }
            remove
            {
                lock (BindingChangedEventLock)
                {
                    BindingChangedEvent -= value;
                }
            }
        }

        protected virtual void OnBindingChanged(EventArgs e)
        {
            EventHandler handler = null;

            lock (BindingChangedEventLock)
            {
                handler = BindingChangedEvent;

                if (handler == null)
                    return;
            }

            handler(this, e);
        }

        #endregion

        #region BindingChanging
        private readonly object BindingChangingEventLock = new object();
        private EventHandler BindingChangingEvent;

        public event EventHandler BindingChanging
        {
            add
            {
                lock (BindingChangingEventLock)
                {
                    BindingChangingEvent += value;
                }
            }
            remove
            {
                lock (BindingChangingEventLock)
                {
                    BindingChangingEvent -= value;
                }
            }
        }

        protected virtual void OnBindingChanging(EventArgs e)
        {
            EventHandler handler = null;

            lock (BindingChangingEventLock)
            {
                handler = BindingChangingEvent;

                if (handler == null)
                    return;
            }

            handler(this, e);
        }

        #endregion

        private IViewModel _ViewModel;

        /// <summary>
        /// Gets or sets the view model.
        /// </summary>
        /// <value>
        /// The view model.
        /// </value>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IViewModel ViewModel
        {
            get
            {
                return _ViewModel;
            }
            set
            {
                if (_ViewModel != null)
                    OnBindingChanging(EventArgs.Empty);
                _ViewModel = value;
                if (_ViewModel != null)
                {
                    _ViewModel.Initialize();
                    OnBindingChanged(EventArgs.Empty);
                }
            }
        }

        private void RemoveBindings(object sender, EventArgs e)
        {
            Commands.UnHandle(ViewModel.Close);
        }

        private void InitializeBindings(object sender, EventArgs e)
        {
            Commands.Handle(ViewModel.Close, ViewModel_CanClose, ViewModel_Close);

            BindFormName();

            this.WatchChange(ViewModel, x => x.ModalViewModel, v => v.ViewModel_ModalViewModelChanged);
        }

        /// <summary>
        /// Binds the name of the form.
        /// </summary>
        protected virtual void BindFormName()
        {
            if (BindNameOnVMState)
                DataBinder.OneWay(this, f => f.Text, ViewModel, v => v.IsDirty, ConverterHelper.FormName, ViewModel.DisplayName);

            this.Text = ViewModel.DisplayName;
        }

        #endregion

        #region Modal sub forms
        private void ViewModel_ModalViewModelChanged(object sender, PropertyChangedEventArgs e)
        {
            if (ViewModel != null && ViewModel.ModalViewModel != null)
            {
                ConfirmViewModel L_Dialog = ViewModel.ModalViewModel as ConfirmViewModel;
                if (L_Dialog != null)
                {
                    L_Dialog.DialogResult = MessageBoxes.Confirm(L_Dialog.Message);
                }
                else
                {
                    ViewBase L_View = ContextHelper.GetView<ViewBase>(ViewModel.ModalViewModel);
                    L_View.ShowDialog();
                }
            }
        }
        #endregion

        #region Command handlers
        protected CommandManager Commands { get; private set; }

        #region ViewModel.Close
        protected virtual void ViewModel_CanClose(object sender, CanExecuteCommandEventArgs e)
        {
            e.CanExecute = true;
        }

        protected virtual void ViewModel_Close(object sender, CommandEventArgs e)
        {
            Message msg = new Message() { Msg = WM_CLOSE };
            base.WndProc(ref msg);
        }
        #endregion
        #endregion

        #region Dispose
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // dispose binder
                DataBinder.Dispose();

                // dispose vm
                if (ViewModel != null)
                {
                    OnBindingChanging(EventArgs.Empty);
                    ViewModel.Dispose();
                }

                // dispose commands
                Commands.Dispose();

                // dispose components
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        #endregion

        //http://www.csharp411.com/c-winforms-form-event-order/

        private const int WM_SYSCOMMAND = 0x112;
        private const int WM_CLOSE = 0x0010;
        private const int SC_CLOSE = 0xF060;

        protected override void WndProc(ref System.Windows.Forms.Message msg)
        {
            if ((msg.Msg == WM_SYSCOMMAND && msg.WParam.ToInt32() == SC_CLOSE) || msg.Msg == WM_CLOSE)
            {
                ViewModel.Close.Execute(ViewModel);
            }
            else
            {
                base.WndProc(ref msg);
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            if (!DesignMode && ViewModel != null)
            {
                ViewModel.LoadData();
                Log.DebugFormat("{0} loading", Name);
            }

            base.OnLoad(e);
        }

        protected override void OnShown(EventArgs e)
        {
            if (!DesignMode && ViewModel != null)
            {
                DataBinder.ResetBindings();
                ViewModel.StartInteraction();
                Log.DebugFormat("{0} shown", Name);
                if (!ViewModel.IsActive)
                {
                    ViewModel.Activate.Execute(null);
                    Log.DebugFormat("{0} activated", Name);
                }
            }
            base.OnShown(e);
        }


        protected override void OnFormClosing(System.Windows.Forms.FormClosingEventArgs e)
        {
            Log.DebugFormat("{0} closing because {1}", Name, e.CloseReason);
            base.OnFormClosing(e);
        }

        protected override void OnFormClosed(FormClosedEventArgs e)
        {
            Log.DebugFormat("{0} closed", Name);
            base.OnFormClosed(e);
        }

        protected override void OnActivated(EventArgs e)
        {
            base.OnActivated(e);
            ViewModel.Activate.Execute(null);
            Log.DebugFormat("{0} activated", Name);
        }

        protected override void OnDeactivate(EventArgs e)
        {
            base.OnDeactivate(e);
            ViewModel.Desactivate.Execute(null);
            Log.DebugFormat("{0} desactivated", Name);
        }

        protected void ViewModel_CheckCancelModifications(object sender, CancelEventArgs e)
        {
            if (ViewModel.IsDirty)
                e.Cancel |= !MessageBoxes.Confirm(Loki.Messages.VMMessages.CONFIRM_EDIT_LOSS);
        }

        #region Export
        /// <summary>
        /// Exports the grids to XLS.
        /// </summary>
        /// <param name="P_Grids">The grids.</param>
        protected void ExportGridsXls(params GridView[] P_Grids)
        {
            foreach (var L_Grid in P_Grids)
            {
                L_Grid.ExportToXls();
            }
        }

        /// <summary>
        /// Exports the grids to XLS.
        /// </summary>
        /// <param name="P_Title">The export title.</param>
        /// <param name="P_Grids">The grids.</param>
        protected void ExportGridsXls(string P_Title, params GridView[] P_Grids)
        {
            foreach (var L_Grid in P_Grids)
            {
                string L_OldCaption = string.Empty;
                bool L_OldCaptionVisible = false;
                if (L_Grid.OptionsView.ShowViewCaption)
                {
                    L_OldCaptionVisible = true;
                    L_OldCaption = L_Grid.ViewCaption;
                }
                if (!string.IsNullOrWhiteSpace(P_Title))
                    L_Grid.ViewCaption = string.Format("{0} - {1}", P_Title, L_Grid.ViewCaption);
                L_Grid.OptionsView.ShowViewCaption = true;

                L_Grid.ExportToXls();

                L_Grid.OptionsView.ShowViewCaption = L_OldCaptionVisible;
                L_Grid.ViewCaption = L_OldCaption;
            }
        }
        #endregion
    }
}
